import {createNamespace} from '../utils';
import {preventDefault} from '../utils/dom/event';
import {TouchMixin} from '../mixins/touch';
import {BindEventMixin} from '../mixins/bind-event';
import {doubleRaf} from '../utils/dom/raf';
import {range} from '../utils/format/number';

var _createNamespace = createNamespace('swipe'),
    createComponent = _createNamespace[0],
    bem = _createNamespace[1];

export default createComponent({
    mixins: [TouchMixin, BindEventMixin(function (bind, isBind) {
        bind(window, 'resize', this.resize, true);

        if (isBind) {
            this.initialize();
        } else {
            this.clear();
        }
    })],
    props: {
        width: Number,
        height: Number,
        autoplay: Number,
        vertical: Boolean,
        indicatorColor: String,
        loop: {
            type: Boolean,
            default: true
        },
        duration: {
            type: Number,
            default: 500
        },
        touchable: {
            type: Boolean,
            default: true
        },
        initialSwipe: {
            type: Number,
            default: 0
        },
        showIndicators: {
            type: Boolean,
            default: true
        },
        stopPropagation: {
            type: Boolean,
            default: true
        }
    },
    data: function data() {
        return {
            computedWidth: 0,
            computedHeight: 0,
            offset: 0,
            active: 0,
            deltaX: 0,
            deltaY: 0,
            swipes: [],
            swiping: false
        };
    },
    watch: {
        swipes: function swipes() {
            this.initialize();
        },
        initialSwipe: function initialSwipe() {
            this.initialize();
        },
        autoplay: function autoplay(_autoplay) {
            if (!_autoplay) {
                this.clear();
            } else {
                this.autoPlay();
            }
        }
    },
    computed: {
        count: function count() {
            return this.swipes.length;
        },
        delta: function delta() {
            return this.vertical ? this.deltaY : this.deltaX;
        },
        size: function size() {
            return this[this.vertical ? 'computedHeight' : 'computedWidth'];
        },
        trackSize: function trackSize() {
            return this.count * this.size;
        },
        activeIndicator: function activeIndicator() {
            return (this.active + this.count) % this.count;
        },
        isCorrectDirection: function isCorrectDirection() {
            var expect = this.vertical ? 'vertical' : 'horizontal';
            return this.direction === expect;
        },
        trackStyle: function trackStyle() {
            var _ref;

            var mainAxis = this.vertical ? 'height' : 'width';
            var crossAxis = this.vertical ? 'width' : 'height';
            return _ref = {}, _ref[mainAxis] = this.trackSize + "px", _ref[crossAxis] = this[crossAxis] ? this[crossAxis] + "px" : '', _ref.transitionDuration = (this.swiping ? 0 : this.duration) + "ms", _ref.transform = "translate" + (this.vertical ? 'Y' : 'X') + "(" + this.offset + "px)", _ref;
        },
        indicatorStyle: function indicatorStyle() {
            return {
                backgroundColor: this.indicatorColor
            };
        },
        minOffset: function minOffset() {
            var rect = this.$el.getBoundingClientRect();
            return (this.vertical ? rect.height : rect.width) - this.size * this.count;
        }
    },
    mounted: function mounted() {
        this.bindTouchEvent(this.$refs.track);
    },
    methods: {
        // initialize swipe position
        initialize: function initialize(active) {
            if (active === void 0) {
                active = this.initialSwipe;
            }

            clearTimeout(this.timer);

            if (this.$el) {
                var rect = this.$el.getBoundingClientRect();
                this.computedWidth = this.width || rect.width;
                this.computedHeight = this.height || rect.height;
            }

            this.swiping = true;
            this.active = active;
            this.offset = this.count > 1 ? -this.size * this.active : 0;
            this.swipes.forEach(function (swipe) {
                swipe.offset = 0;
            });
            this.autoPlay();
        },
        // @exposed-api
        resize: function resize() {
            this.initialize(this.activeIndicator);
        },
        onTouchStart: function onTouchStart(event) {
            if (!this.touchable) return;
            this.clear();
            this.touchStart(event);
            this.correctPosition();
        },
        onTouchMove: function onTouchMove(event) {
            if (!this.touchable || !this.swiping) return;
            this.touchMove(event);

            if (this.isCorrectDirection) {
                preventDefault(event, this.stopPropagation);
                this.move({
                    offset: this.delta
                });
            }
        },
        onTouchEnd: function onTouchEnd() {
            if (!this.touchable || !this.swiping) return;

            if (this.delta && this.isCorrectDirection) {
                var offset = this.vertical ? this.offsetY : this.offsetX;
                this.move({
                    pace: offset > 0 ? this.delta > 0 ? -1 : 1 : 0,
                    emitChange: true
                });
            }

            this.swiping = false;
            this.autoPlay();
        },
        getTargetActive: function getTargetActive(pace) {
            var active = this.active,
                count = this.count;

            if (pace) {
                if (this.loop) {
                    return range(active + pace, -1, count);
                }

                return range(active + pace, 0, count - 1);
            }

            return active;
        },
        getTargetOffset: function getTargetOffset(targetActive, offset) {
            var currentPosition = targetActive * this.size;

            if (!this.loop) {
                currentPosition = Math.min(currentPosition, -this.minOffset);
            }

            var targetOffset = Math.round(offset - currentPosition);

            if (!this.loop) {
                targetOffset = range(targetOffset, this.minOffset, 0);
            }

            return targetOffset;
        },
        move: function move(_ref2) {
            var _ref2$pace = _ref2.pace,
                pace = _ref2$pace === void 0 ? 0 : _ref2$pace,
                _ref2$offset = _ref2.offset,
                offset = _ref2$offset === void 0 ? 0 : _ref2$offset,
                emitChange = _ref2.emitChange;
            var loop = this.loop,
                count = this.count,
                active = this.active,
                swipes = this.swipes,
                trackSize = this.trackSize,
                minOffset = this.minOffset;

            if (count <= 1) {
                return;
            }

            var targetActive = this.getTargetActive(pace);
            var targetOffset = this.getTargetOffset(targetActive, offset); // auto move first and last swipe in loop mode

            if (loop) {
                if (swipes[0]) {
                    var outRightBound = targetOffset < minOffset;
                    swipes[0].offset = outRightBound ? trackSize : 0;
                }

                if (swipes[count - 1]) {
                    var outLeftBound = targetOffset > 0;
                    swipes[count - 1].offset = outLeftBound ? -trackSize : 0;
                }
            }

            this.active = targetActive;
            this.offset = targetOffset;

            if (emitChange && targetActive !== active) {
                this.$emit('change', this.activeIndicator);
            }
        },
        // @exposed-api
        prev: function prev() {
            var _this = this;

            this.correctPosition();
            this.resetTouchStatus();
            doubleRaf(function () {
                _this.swiping = false;

                _this.move({
                    pace: -1,
                    emitChange: true
                });
            });
        },
        // @exposed-api
        next: function next() {
            var _this2 = this;

            this.correctPosition();
            this.resetTouchStatus();
            doubleRaf(function () {
                _this2.swiping = false;

                _this2.move({
                    pace: 1,
                    emitChange: true
                });
            });
        },
        // @exposed-api
        swipeTo: function swipeTo(index, options) {
            var _this3 = this;

            if (options === void 0) {
                options = {};
            }

            this.correctPosition();
            this.resetTouchStatus();
            doubleRaf(function () {
                var targetIndex;

                if (_this3.loop && index === _this3.count) {
                    targetIndex = _this3.active === 0 ? 0 : index;
                } else {
                    targetIndex = index % _this3.count;
                }

                if (options.immediate) {
                    doubleRaf(function () {
                        _this3.swiping = false;
                    });
                } else {
                    _this3.swiping = false;
                }

                _this3.move({
                    pace: targetIndex - _this3.active,
                    emitChange: true
                });
            });
        },
        correctPosition: function correctPosition() {
            this.swiping = true;

            if (this.active <= -1) {
                this.move({
                    pace: this.count
                });
            }

            if (this.active >= this.count) {
                this.move({
                    pace: -this.count
                });
            }
        },
        clear: function clear() {
            clearTimeout(this.timer);
        },
        autoPlay: function autoPlay() {
            var _this4 = this;

            var autoplay = this.autoplay;

            if (autoplay && this.count > 1) {
                this.clear();
                this.timer = setTimeout(function () {
                    _this4.next();

                    _this4.autoPlay();
                }, autoplay);
            }
        },
        genIndicator: function genIndicator() {
            var _this5 = this;

            var h = this.$createElement;
            var count = this.count,
                activeIndicator = this.activeIndicator;
            var slot = this.slots('indicator');

            if (slot) {
                return slot;
            }

            if (this.showIndicators && count > 1) {
                return h("div", {
                    "class": bem('indicators', {
                        vertical: this.vertical
                    })
                }, [Array.apply(void 0, Array(count)).map(function (empty, index) {
                    return h("i", {
                        "class": bem('indicator', {
                            active: index === activeIndicator
                        }),
                        "style": index === activeIndicator ? _this5.indicatorStyle : null
                    });
                })]);
            }
        }
    },
    render: function render() {
        var h = arguments[0];
        return h("div", {
            "class": bem()
        }, [h("div", {
            "ref": "track",
            "style": this.trackStyle,
            "class": bem('track')
        }, [this.slots()]), this.genIndicator()]);
    }
});